﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Search;

using ERPStore.Extensions;
using ERPStore.Indexers.Lucene.Models;

using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Analysis.Standard;

namespace ERPStore.Indexers.Lucene.Repositories
{
	public class LuceneRepository
	{
		public LuceneRepository(Logging.ILogger logger,
			Models.Settings settings)
		{
			this.IndexPath = settings.Path + "\\Catalog";
			this.Logger = logger;
		}

		protected string IndexPath { get; private set; }
		protected Logging.ILogger Logger { get; private set; }

		public void AddDocument(Document doc)
		{
			var writer = CreateIndexWriter();
			try
			{
				writer.AddDocument(doc);
			}
			catch(Exception ex)
			{
				Logger.Error(ex);
			}
			finally
			{
				writer.Optimize();
				writer.Close();
			}
		}

		public void DeleteDocument(Query query)
		{
			var writer = CreateIndexWriter();
			try
			{
				writer.DeleteDocuments(query);
			}
			catch (Exception ex)
			{
				Logger.Error(ex);
			}
			finally
			{
				writer.Close();
			}
		}

		public IList<Document> GetDocumentList(Query query, int page, int pageSize, out int count, Sort sort, bool useScoreDoc, bool substituteVariation, bool sortByScore = true)
		{
			count = 0;
			if (query == null)
			{
				return null;
			}

			var directoryInfo = new System.IO.DirectoryInfo(IndexPath);
			var lockFactory = new global::Lucene.Net.Store.NoLockFactory();
			var directory = global::Lucene.Net.Store.FSDirectory.Open(directoryInfo, lockFactory);

			var result = new List<Document>();
			IndexSearcher searcher = null;

			try
			{
				searcher = new IndexSearcher(directory, true);
				TopDocsCollector collector = null;
				if (useScoreDoc
					|| sort == null)
				{
					var numHits = Math.Min((page + 1) * pageSize, searcher.MaxDoc());
					collector = TopScoreDocCollector.create(numHits, false);
				}
				else
				{
					var numHits = Math.Max(Int16.MaxValue, searcher.MaxDoc());
					collector = TopFieldCollector.create(sort, numHits, false, true, false, true);
				}

				Logger.Debug("lucene query : {0}\r\n", query.ToString());

				searcher.Search(query, collector);

				count = collector.GetTotalHits();
				Logger.Debug("{0} resultat(s)\r\nquery :\r\n{1}", count, query);

				IEnumerable<ScoreDoc> docs = collector.TopDocs().ScoreDocs;
				if (sortByScore)
				{
					docs = docs.OrderByDescending(i => i.score);
				}
				docs = docs.ToList();

				result = docs.Skip(page * pageSize)
								.Take(pageSize)
								.Select(sd => searcher.Doc(sd.doc))
								.ToList();

			}
			catch (System.IO.IOException)
			{
				// Do nothing
			}
			catch (Exception ex)
			{
				// ex.Data.Add("searchpath", IndexPath);
				var queryString = string.Empty;
				try
				{
					queryString = query.ToString();
				}
				catch { }
				ex.Data.Add("CatalogService:searchquery", queryString);
				// ex.Data.Add("searchsort", sort);
				Logger.Error(ex);
			}
			finally
			{
				if (searcher != null)
				{
					searcher.Close();
				}
				if (directory != null)
				{
					directory.Close();
				}
			}

			return result;
		}

		public bool IsEmpty()
		{
			var directoryInfo = new System.IO.DirectoryInfo(IndexPath);
			if (!directoryInfo.Exists)
			{
				return false;
			}
			var lockFactory = new global::Lucene.Net.Store.NoLockFactory();
			var directory = global::Lucene.Net.Store.FSDirectory.Open(directoryInfo, lockFactory);

			IndexReader reader = null;

			try
			{
				reader = IndexReader.Open(directory, true);
				return reader.NumDocs() == 0;
			}
			catch(Exception ex)
			{
				Logger.Error(ex);
			}
			finally
			{
				if (reader != null)
				{
					reader.Close();
				}
			}
			return true;
		}


		private IndexWriter CreateIndexWriter()
		{
			var directoryInfo = new System.IO.DirectoryInfo(IndexPath);
			if (!directoryInfo.Exists)
			{
				System.IO.Directory.CreateDirectory(IndexPath);
			}

			var lockFactory = new global::Lucene.Net.Store.NoLockFactory();
			var directory = global::Lucene.Net.Store.FSDirectory.Open(directoryInfo, lockFactory);
			var analyzer = new StandardAnalyzer(global::Lucene.Net.Util.Version.LUCENE_29);
			var indexWriter = new IndexWriter(directory, analyzer, false, global::Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
			indexWriter.SetUseCompoundFile(true);
			return indexWriter;
		}
	}
}
